package com.zhdl.hardware.io.smartLink.repository.impl;

import com.google.common.eventbus.Subscribe;
import com.project.command.faq.event.behavior.BehaviorPerform;
import com.project.command.instruction.strategy.process.data.AfterStrategyParam;
import com.project.common.util.ByteHelper;
import com.zhdl.common.eventbus.center.EventBusCenter;
import com.zhdl.hardware.io.smartLink.repository.IOCmdHandleDao;
import com.zhdl.modules.tools.CommonCallback;
import com.zhdl.modules.tools.IntToHexUtil;
import com.zhdl.network.modbus.dto.ModbusDto;
import com.zhdl.network.modbus.request.WriteSingleKeepRegisterReq;
import com.zhdl.network.modbustcp.ModbusTcpRespPkg;
import com.zhdl.network.strategy.common.ProtocolContext;
import com.zhdl.network.strategy.modbustcp.ModbusTcpStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
public class IOCmdHandleDaoImpl implements IOCmdHandleDao {

    /**
     * IO网口地址
     */
    public String port;

    /**
     * 通信协议处理
     */
    public ProtocolContext protocolContext;

    /**
     * Callback 回调管理
     */
    public Map<String, CommonCallback<byte[]>> commonCallbackMap = new ConcurrentHashMap<>();

    @Resource
    private BehaviorPerform behaviorPerform;

    /**
     * 初始化
     *
     * @param port 串口/网口
     */
    public void init(String port) {
        EventBusCenter.getEventBus().register(this);
        protocolContext = new ProtocolContext(new ModbusTcpStrategy(port, behaviorPerform));
        this.port = port;
    }

    /**
     * eventbus 数据接收处理
     *
     * @param event after返回的消息
     */
    @Subscribe
    public void dataReception(AfterStrategyParam event) {
        /* 判断策略 - 判断当前串口 */
        if (port.equals(event.getPortKey())) {
            /* 获取电机指令返回的数据 */
            /* 此处接收串口或网口客户端回应代码,并处理 */
            List<ModbusDto> list = event.getNewData();
            ModbusDto modbusDto = list.get(0);
            String instruction = event.getInstruction();
            log.info("当前发送的指令为:" + instruction);
            instruction = instruction.replaceAll(" ", "");
            /* 遍历存放指令的集合，如何对应的map包含有指令，则取出来返回获取的数据 */
            instruction = instruction.toUpperCase();
            for (String cmd : commonCallbackMap.keySet()) {
                String temp = cmd.toUpperCase();
                if (temp.contains(instruction)) {
                    commonCallbackMap.get(cmd).statusCallback(modbusDto.getUnitBuff());
                    log.info("当前指令:" + instruction + ",返回的数据为:" + Arrays.toString(modbusDto.getUnitBuff()));
                    commonCallbackMap.remove(cmd);
                }
            }
        }
    }

    /**
     * IO-读取线圈 功能码01
     * 读取所有信息
     */
    @Override
    public void ioReadCoilSignal(String value, CommonCallback<byte[]> callback) {
        WriteSingleKeepRegisterReq writeManyKeepRegisterReq = new WriteSingleKeepRegisterReq();
        /* 从站ID 101 */
        writeManyKeepRegisterReq.setId("101");
        /* 参数 需要写入的值 */
        writeManyKeepRegisterReq.setStartAddr("0000");
        writeManyKeepRegisterReq.setWriteValue("00"+value);
        try {
            byte[] bytes = ModbusTcpRespPkg.read01(writeManyKeepRegisterReq);
            protocolContext.sendCmd(ByteHelper.bytesArrayToHexString(bytes));
            commonCallbackMap.put(ByteHelper.bytesArrayToHexString(bytes), callback);
            log.info("IO-开始读取功能码为01的线圈输入信号");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * IO-读取离散量输入 功能码02
     * 读取所有信息
     */
    @Override
    public void ioReadDiscreteSignal(String value, CommonCallback<byte[]> callback) {
        WriteSingleKeepRegisterReq writeManyKeepRegisterReq = new WriteSingleKeepRegisterReq();
        /* 从站ID 101 */
        writeManyKeepRegisterReq.setId("101");
        writeManyKeepRegisterReq.setStartAddr("0000");
        /* 参数 需要写入的值 */
        writeManyKeepRegisterReq.setWriteValue("00"+value);
        try {
            byte[] bytes = ModbusTcpRespPkg.read02(writeManyKeepRegisterReq);
            protocolContext.sendCmd(ByteHelper.bytesArrayToHexString(bytes));
            commonCallbackMap.put(ByteHelper.bytesArrayToHexString(bytes), callback);
            log.info("IO-开始读取功能码为02的离散量输入信号");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * IO-写入线圈 功能码05
     * 写入输出量
     *
     * @param address 地址
     * @param open open ? FF00:0000
     * @param callback 回调
     */
    @Override
    public void ioWriteCoilSignal(int address, String open, CommonCallback<byte[]> callback) {
        WriteSingleKeepRegisterReq writeManyKeepRegisterReq = new WriteSingleKeepRegisterReq();
        //smartLink的从站地址默认为:101
        writeManyKeepRegisterReq.setId("101");
        writeManyKeepRegisterReq.setStartAddr(IntToHexUtil.shortToHex(address));
        //writeManyKeepRegisterReq.setWriteValue(open ? "FF00" : "0000");
        writeManyKeepRegisterReq.setWriteValue(open);
        try {
            byte[] bytes = ModbusTcpRespPkg.write05(writeManyKeepRegisterReq);
            protocolContext.sendCmd(ByteHelper.bytesArrayToHexString(bytes));
            commonCallbackMap.put(ByteHelper.bytesArrayToHexString(bytes), callback);
            log.info("IO-05功能码拼装的指令为：" + ByteHelper.bytesArrayToHexString(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * IO-写入多个线圈 功能码0F
     * 写入输出量
     *
     * @param address 地址
     * @param open open ? 01:02
     * @param callback 回调
     */
    @Override
    public void ioWriteDoubleCoilSignal(int address, boolean open, CommonCallback<byte[]> callback) {
        WriteSingleKeepRegisterReq writeManyKeepRegisterReq = new WriteSingleKeepRegisterReq();
        ///smartLink的从站地址默认为:101
        writeManyKeepRegisterReq.setId("101");
        writeManyKeepRegisterReq.setStartAddr(IntToHexUtil.shortToHex(address));
        writeManyKeepRegisterReq.setWriteValue(open ? "01" : "02");
        //writeManyKeepRegisterReq.setWriteValue(open);
        try {
            byte[] bytes = ModbusTcpRespPkg.WriteDoubleCoil(writeManyKeepRegisterReq);
            protocolContext.sendCmd(ByteHelper.bytesArrayToHexString(bytes));
            commonCallbackMap.put( ByteHelper.bytesArrayToHexString(bytes),callback);
            log.info("IO-0F功能码拼装的指令为：" + ByteHelper.bytesArrayToHexString(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
